#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#

"""

curl -d 'requestData={"action": "door.request", "channel": "4", "req_params": {"door_id": 123456789,
"req_no": 1, "sign": "TODO: encrypt req_no"}, "session_id": null, "user_type": "0", "version":
"1.0.0"}' http://118.244.203.178:8080/test/servlet/myServlet

response: 
{"ret_code":true,"ret_msg":"success","rsp_params":{"count":1,"emsi_1":"abcdefghijkl"}}

"""

import urllib
import urllib2
import json
import sqlite3
import base64
import binascii

from M2Crypto import RSA, X509

# Door lock version
DOOR_VERSION = "1.0.0"
ACTION_REQEUST = "door.request"
ACTION_UPDATE = "door.update"
SERVER_ADDRESS = "http://127.0.0.1/test.php"
#SERVER_ADDRESS = "http://118.244.203.178:8080/test/servlet/myServlet"
CERT = 'example.crt'

CREATE_SQLITE_TABLE_SQL = '''create table if not exists catalog (id integer primary key,
pid integer,name varchar(10) UNIQUE,nickname text NULL)'''

class doorclient(object):
    def __init__(self):
        self.server_addr = SERVER_ADDRESS
        self.doorid = 123456789
        self.seq_no = 0
        self.update_no = 0
        self.cert = X509.load_cert(CERT)
        self.puk = self.cert.get_pubkey().get_rsa()

    def sign_with_cert_public_key(self, seqno):
        # FIXME: seqno is integer
        # and output is binary data
        # use base64
        encrypted_raw = self.puk.public_encrypt(hex(seqno), RSA.pkcs1_padding)
        #return binascii.b2a_hex()
        #return binascii.b2a_base64(encrypted_raw)  # will append a \n
        return base64.b64encode(encrypted_raw)

    def post(self, action, data):
        comm_data = {
            'version': DOOR_VERSION, 
            'user_type': '0',
            'session_id': None,
            'channel': '4' 
        }

        comm_data['action'] = action
        comm_data['req_params'] = data
        #print comm_data

        #jdata = json.dumps(comm_data, indent=4, sort_keys=True)
        jdata = json.dumps(comm_data, sort_keys=True)
        jdata = 'requestData=' + jdata
        print jdata
        req = urllib2.Request(self.server_addr, jdata)
        try:
            response = urllib2.urlopen(req, timeout = 3)
            print response.read()
        except urllib2.HTTPError, e:
            print 'The server could not fullfill the request, status ', e.code
        except urllib2.URLError, e:
            print 'failed to reach a server, reason ', e.reason

    def request(self):
        self.seq_no += 1
        data = {}
        data['door_id'] = self.doorid
        data['req_no'] = self.seq_no
        #data['sign'] = 'TODO: encrypt req_no'
        data['sign'] = self.sign_with_cert_public_key(self.seq_no)
        print data['sign']
        self.post(ACTION_REQEUST, data)

    def update(self):
        self.update_no += 1

        req_params = {}
        req_params['door_id'] = self.doorid
        req_params['update_no'] = self.update_no
        #req_params['sign'] = 'TODO: encrypt update_no'
        req_params['sign'] = self.sign_with_cert_public_key(self.update_no)

        count = 10

        for i in range(1, 11):
            req_params['json_door' + str(i)] = {'user_id': str(i), 'time': str(i)}

        #print req_params

        self.post(ACTION_UPDATE, req_params)

if __name__ == "__main__":
    doorclient = doorclient()
    
    cx = sqlite3.connect("test.db")
    cu = cx.cursor()
    cu.execute(CREATE_SQLITE_TABLE_SQL)
    

    doorclient.request()
    #doorclient.request()
    #doorclient.update()
    #doorclient.update()
    doorclient.update()
    

